import os
import yaml
import logging
from pydantic import BaseModel, field_validator
from typing import List
import psutil

def get_base_path():
    import sys
    # 如果通过pyinstaller打包，则找到二进制文件的同级目录
    if getattr(sys, 'frozen', False):
        return os.path.dirname(sys.executable)
    return os.path.dirname(__file__)

def get_default_config_path():
    base_path = get_base_path()
    config_path = os.path.join(base_path, "config.yaml")
    logging.info(f"获取配置文件路径: {config_path}")
    return config_path

def get_log_path():
    base_path = get_base_path()
    log_path = os.path.join(base_path, "logs")
    logging.info(f"获取日志目录: {log_path}")
    return log_path

class Config(BaseModel):
    available_devices: List[str] = []
    reserved_mem: int = 1024  # gpu显存MB
    reserved_cpu_mem: int = 1024  # 默认预留1GB内存
    max_retries: int = 3
    log_dir: str = get_log_path()
    check_interval: int = 5
    safe_commands: List[str] = ["python", "train", "bash"]
    cpu_total_mem: int = int(psutil.virtual_memory().total / (1024 ** 2))  # 使用系统总CPU内存(MB)
    server_pid: int = 0

    @field_validator("available_devices")
    def validate_devices(cls, value):
        seen_devices = set()
        for d in value:
            if d in seen_devices:
                raise ValueError(f"设备重复: {d}")
            seen_devices.add(d)
            if str(d) != "cpu" and not d.startswith("cuda:"):
                raise ValueError(f"无效设备格式: {d}")
            if d.startswith("cuda:") and not d.split(":")[1].isdigit():
                raise ValueError(f"无效设备编号: {d}")
        return value

    @classmethod
    def load(cls, path: str = get_default_config_path()):
        try:
            if os.path.exists(path):
                with open(path) as f:
                    return cls(**yaml.safe_load(f))
            return cls()
        except (yaml.YAMLError, PermissionError, FileNotFoundError) as e:
            logging.warning(f"配置加载失败: {str(e)}")
            return cls()

    def save(self, path: str = get_default_config_path()):
        with open(path, "w") as f:
            yaml.safe_dump(self.model_dump(by_alias=False), f, sort_keys=False, indent=2)
